﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Diagnostics.Contracts;

namespace SimpleIR
{
	/// <summary>
	/// This interface defines the abstract concept of "root" references in the program: local variables or static fields.
	/// </summary>
	public interface IRRootIdentifier
	{
		String RootNameString();
	}

	/// <summary>
	/// Represents a single variable name.
	/// </summary>
	public sealed class IRVarName : IRCompareableName, IRRootIdentifier
	{
		private readonly String m_vn;
		
		[ContractInvariantMethod]
		private void ObjectInvariant()
		{ Contract.Invariant(!String.IsNullOrEmpty(this.m_vn)); }

		internal IRVarName(String name)
			: base()
		{
			Contract.Requires(!String.IsNullOrEmpty(name));

			this.m_vn = name;
		}

		/// <summary>
		/// Get the string name of the variable.
		/// </summary>
		public String NameString 
		{ 
			get
			{
				Contract.Ensures(!String.IsNullOrEmpty(Contract.Result<String>()));

				return this.m_vn; 
			} 
		}

		public override String ToString() { return this.m_vn; }

		public String RootNameString()
		{ return this.NameString; }
	}

	/// <summary>
	/// Represents a single static field.
	/// </summary>
	public sealed class IRStaticField : IRCompareableName, IRRootIdentifier
	{
		private readonly IRType m_defInClass;
		private readonly String m_fname;
		private readonly IRType m_ftype;

		[ContractInvariantMethod]
		private void ObjectInvariant()
		{ 
			Contract.Invariant(this.m_defInClass != null);
			Contract.Invariant(!String.IsNullOrEmpty(this.m_fname));
			Contract.Invariant(this.m_ftype != null);
		}

		internal IRStaticField(IRType defClass, String name, IRType fieldType)
			: base()
		{
			Contract.Requires(defClass != null);
			Contract.Requires(!String.IsNullOrEmpty(name));
			Contract.Requires(fieldType != null);

			this.m_defInClass = defClass;
			this.m_fname = name;
			this.m_ftype = fieldType;
		}

		/// <summary>
		/// Return the class type where this field is defined.
		/// </summary>
		public IRType DefinedInClass 
		{ 
			get 
			{
				Contract.Ensures(Contract.Result<IRType>() != null);

				return this.m_defInClass; 
			} 
		}

		/// <summary>
		/// Return the type that is stored in this field.
		/// </summary>
		public IRType FieldType 
		{ 
			get 
			{
				Contract.Ensures(Contract.Result<IRType>() != null);

				return this.m_ftype; 
			} 
		}

		/// <summary>
		/// Return the name of this field.
		/// </summary>
		public String FieldName 
		{ 
			get 
			{
				Contract.Ensures(!String.IsNullOrEmpty(Contract.Result<String>()));

				return this.m_fname; 
			} 
		}

		public override String ToString()
		{ return this.m_defInClass.ToString() + "." + this.m_fname; }

		public string RootNameString()
		{ return this.m_defInClass.ToString() + "." + this.m_fname; }
	}
}
